<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Spring学习(2)IoC | 后端学习记录</title><meta name="keywords" content="Spring"><meta name="author" content="h0ss"><meta name="copyright" content="h0ss"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="接Spring学习(1)：https:&#x2F;&#x2F;h0ss.gitee.io&#x2F;2021&#x2F;07&#x2F;30&#x2F;Spring学习-1-快速上手&#x2F; 3、IoC部分3.1  IoC容器org.springframework.context.ApplicationContext接口代表了Spring IoC容器，它负责实例化、配置、组装bean。通过快速上手了解到，可以将类的相关声明写在配置文件中，（此外还可以使用注解驱动">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring学习(2)IoC">
<meta property="og:url" content="https://blog.gpnusz.cn/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-2-IoC/index.html">
<meta property="og:site_name" content="后端学习记录">
<meta property="og:description" content="接Spring学习(1)：https:&#x2F;&#x2F;h0ss.gitee.io&#x2F;2021&#x2F;07&#x2F;30&#x2F;Spring学习-1-快速上手&#x2F; 3、IoC部分3.1  IoC容器org.springframework.context.ApplicationContext接口代表了Spring IoC容器，它负责实例化、配置、组装bean。通过快速上手了解到，可以将类的相关声明写在配置文件中，（此外还可以使用注解驱动">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://www.hualigs.cn/image/610c2015e15b8.jpg">
<meta property="article:published_time" content="2021-07-29T17:35:55.000Z">
<meta property="article:modified_time" content="2022-07-28T07:11:30.559Z">
<meta property="article:author" content="h0ss">
<meta property="article:tag" content="Spring">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://www.hualigs.cn/image/610c2015e15b8.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://blog.gpnusz.cn/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-2-IoC/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2022-07-28 15:11:30'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">后端学习记录</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">Spring学习(2)IoC</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-07-29T17:35:55.000Z" title="发表于 2021-07-30 01:35:55">2021-07-30</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-28T07:11:30.559Z" title="更新于 2022-07-28 15:11:30">2022-07-28</time></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">5k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>19分钟</span></span></div></div></div><article class="post-content" id="article-container"><p>接Spring学习(1)：<a target="_blank" rel="noopener" href="https://h0ss.gitee.io/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-1-%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/">https://h0ss.gitee.io/2021/07/30/Spring学习-1-快速上手/</a></p>
<h3 id="3、IoC部分"><a href="#3、IoC部分" class="headerlink" title="3、IoC部分"></a>3、IoC部分</h3><h4 id="3-1-IoC容器"><a href="#3-1-IoC容器" class="headerlink" title="3.1  IoC容器"></a>3.1  IoC容器</h4><p><code>org.springframework.context.ApplicationContext</code>接口代表了Spring IoC容器，它负责<strong>实例化、配置、组装bean</strong>。通过快速上手了解到，可以将类的相关声明写在配置文件中，（此外还可以使用注解驱动开发，下面会细讲），之后将资源加载到IoC容器中，通过容器去管理。而在通过IoC容器读取Bean的实例之前，需要先将IoC容器本身实例化。在web应用中通常都是通过<code>ClassPathXmlApplicationContext</code>在classpath下加载配置文件（基于xml配置），生成一个IoC容器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ApplicationContext ioc = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">&quot;ioc.xml&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>实际上这里还可以返回成<code>BeanFactory</code>，这是IoC容器的基本实现，它的特点是延迟载入所有Bean；而<code>ApplicationContext</code>是BeanFactory的子接口，它简化了与 AOP 的整合、消息机制、事件机制，以及对 Web 环境的扩展，同时保持基本特性的兼容。Spring官方文档中推荐使用这种方式。</p>
<blockquote>
<p>You should use an ApplicationContext unless you have a good reason for not doing so. </p>
</blockquote>
<p>除此之外还可以通过<code>FileSystemXmlApplicationContext</code>从文件系统或者URL装载XML配置文件；<code>XmlWebApplicationContext</code>和<code>XmlPortletApplicationContext</code>用于Web和入口应用程序。</p>
<h4 id="3-2-依赖查找（基于xml）"><a href="#3-2-依赖查找（基于xml）" class="headerlink" title="3.2 依赖查找（基于xml）"></a>3.2 依赖查找（基于xml）</h4><p>依赖查找指的是<strong>容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象</strong>。通过这种方式来查找对象需要调用相关的api。上面使用到的 <code>ioc.getBean(&quot;person&quot;)</code>即是依赖查找。</p>
<h5 id="1）基于上下文的依赖查找："><a href="#1）基于上下文的依赖查找：" class="headerlink" title="1）基于上下文的依赖查找："></a>1）基于上下文的依赖查找：</h5><p>①通过对象的id获取，传入配置在xml文件中的对象的id，也就是快速上手的那种获取方法；</p>
<p>②通过对象类型去查找，需要注意的是，如果同一个类型的bean在XML文件中配置了多个，则获取时会抛出异常，所以同一个类型的bean在容器中必须是唯一的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Person person = ioc.getBean(Person.class);</span><br></pre></td></tr></table></figure>

<p>③通过使用类型和id参数搭配的方式查找</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Person person = ioc.getBean(<span class="string">&quot;person&quot;</span>, Person.class);</span><br></pre></td></tr></table></figure>

<p>④通过getBeansOfType方法获取传入接口/抽象类的实现类/子类（假设MyInterface是接口）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;String, MyInterface&gt; beans = ioc.getBeansOfType(MyInterface.class);</span><br></pre></td></tr></table></figure>

<h5 id="2）查找IoC容器所有bean"><a href="#2）查找IoC容器所有bean" class="headerlink" title="2）查找IoC容器所有bean"></a>2）查找IoC容器所有bean</h5><p>如果需要查找出IoC容器中的所有bean，还可以使用<code>getBeanDefinitionNames</code>方法，这个方法会获取所有bean的id，接着可以根据id去找出对应的bean</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String[] beanNames = ioc.getBeanDefinitionNames();</span><br></pre></td></tr></table></figure>

<h5 id="3）延迟查找"><a href="#3）延迟查找" class="headerlink" title="3）延迟查找"></a>3）延迟查找</h5><p>对于一些特殊的场景，需要依赖容器中的某些特定的 Bean ，但当它们不存在时需要有方法去处理对应的情况，而不是抛异常。假设我们现在Person类没有在IoC容器中，那么如果直接getBean会报<code>NoSuchBeanDefinitionException</code>异常，我们需要的是让他延迟查找这个bean，怎么做？</p>
<p>在<code>ApplicationContext</code>中有一个方法叫 <code>getBeanProvider</code>，传入bean的类信息，得到的是一个ObjectProvider&lt;&gt;对象，只有在调用该对象的getObject方法试图取出里面的bean对象时才会抛异常。</p>
<p>再进一步，如果bean不存在，我不想让它抛异常，怎么做？</p>
<p>ObjectProvider中还有一个方法叫<code>getIfAvailable</code>，在bean存在时会获取到bean，而获取bean失败时返回null而非异常。</p>
<h4 id="3-3-依赖注入（基于xml）"><a href="#3-3-依赖注入（基于xml）" class="headerlink" title="3.3 依赖注入（基于xml）"></a>3.3 依赖注入（基于xml）</h4><p>现在我们已经可以从IoC容器中获取到对象了，但可以发现这些对象都是没有具体的属性的，而依赖注入是一个过程，也就是说对于这些属性我们不用自己手动去传，而是交给IoC容器去处理，让容器通过反射的方式去进行对象的注入。</p>
<p>对Person对象进行改造：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">	<span class="keyword">private</span> String name;</span><br><span class="line">	<span class="keyword">private</span> Integer age;</span><br><span class="line">	<span class="keyword">private</span> String phone;</span><br><span class="line">	<span class="keyword">private</span> Car car;</span><br><span class="line">	<span class="keyword">private</span> List&lt;Car&gt; CarList;</span><br><span class="line">	<span class="keyword">private</span> Map&lt;String, Object&gt; testMap;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name, Integer age, String phone)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.name = name;</span><br><span class="line">		<span class="keyword">this</span>.age = age;</span><br><span class="line">		<span class="keyword">this</span>.phone = phone;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTestMap</span><span class="params">(Map&lt;String, Object&gt; testMap)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.testMap = testMap;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCar</span><span class="params">(Car car)</span> </span>&#123;<span class="keyword">this</span>.car = car;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCarList</span><span class="params">(List&lt;Car&gt; carList)</span> </span>&#123;CarList = carList;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setnameForPerson</span><span class="params">(String name)</span> </span>&#123;<span class="keyword">this</span>.name = name;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(Integer age)</span> </span>&#123;<span class="keyword">this</span>.age = age;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPhone</span><span class="params">(String phone)</span> </span>&#123;<span class="keyword">this</span>.phone = phone;&#125;</span><br><span class="line">    <span class="comment">//重写toString方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>依赖注入有两个主要的形式，一个是基于构造函数的依赖注入，一个是基于 Setter 的依赖注入。</p>
<h5 id="1）基于Setter的依赖注入；"><a href="#1）基于Setter的依赖注入；" class="headerlink" title="1）基于Setter的依赖注入；"></a>1）基于Setter的依赖注入；</h5><p>在xml文件中进行配置，使用property标签，name属性为对应的setXx方法的这个Xx，而不是在类中定义的属性，value为属性值：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 可以看到这里写的是nameForPerson并非name --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;nameForPerson&quot;</span> <span class="attr">value</span>=<span class="string">&quot;zhangsan&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;16&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;phone&quot;</span> <span class="attr">value</span>=<span class="string">&quot;135000&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="2）基于构造器的依赖注入；"><a href="#2）基于构造器的依赖注入；" class="headerlink" title="2）基于构造器的依赖注入；"></a>2）基于构造器的依赖注入；</h5><p>在xml文件中，使用constructor-arg标签进行赋值，name为构造器参数名，value为值：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person2&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">	<span class="comment">&lt;!-- 调用有参构造器进行创建对象并赋值 --&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">value</span>=<span class="string">&quot;lisi&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;18&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;phone&quot;</span> <span class="attr">value</span>=<span class="string">&quot;135111&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><em>这里也可以省略constructor-arg的name属性，但是必须按照构造器顺序写value</em> </p>
<h5 id="3）为bean属性赋值的其他情况"><a href="#3）为bean属性赋值的其他情况" class="headerlink" title="3）为bean属性赋值的其他情况"></a>3）为bean属性赋值的其他情况</h5><p>①为属性赋值null；</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person3&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">null</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>②为引用类型的属性赋值；</p>
<p>创建一个Car类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String carName;</span><br><span class="line">    <span class="keyword">private</span> Integer price;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCarName</span><span class="params">(String carName)</span> </span>&#123;<span class="keyword">this</span>.carName = carName;&#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPrice</span><span class="params">(Integer price)</span> </span>&#123;<span class="keyword">this</span>.price = price;&#125;</span><br><span class="line">    <span class="comment">//重写toString</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>方式1：使用bean标签赋值</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person4&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;car&quot;</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Car&quot;</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;carName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;benz&quot;</span>/&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;price&quot;</span> <span class="attr">value</span>=<span class="string">&quot;8800&quot;</span>/&gt;</span></span><br><span class="line">		<span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>方式2：引用外部bean</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;car1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Car&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;carName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;bmw&quot;</span>/&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;price&quot;</span> <span class="attr">value</span>=<span class="string">&quot;3380&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person4&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;car&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;car1&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>③为集合类型属性赋值；</p>
<p>1）为List属性赋值：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person5&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;carList&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 这里的list标签相当于 list = new ArrayList&lt;&gt;(); --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">list</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 方式一：直接写内部bean --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Car&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;carName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;byd&quot;</span>/&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;price&quot;</span> <span class="attr">value</span>=<span class="string">&quot;6600&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 方法二：引用外部bean --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;car1&quot;</span>/&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- list中还有value标签可以赋单值 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">list</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>2）为map属性赋值：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;person6&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Person&quot;</span>&gt;</span>	</span><br><span class="line">	<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;testMap&quot;</span>&gt;</span></span><br><span class="line">		<span class="comment">&lt;!-- 1.map标签相当于 map = new LinkedHashMap&lt;&gt;(); --&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">map</span>&gt;</span></span><br><span class="line">			<span class="comment">&lt;!-- 方式一：在value中直接写值 --&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;key01&quot;</span> <span class="attr">value</span>=<span class="string">&quot;zhangsan&quot;</span>/&gt;</span></span><br><span class="line">			<span class="comment">&lt;!-- 方式二：value是一个引用bean的内容 --&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;key02&quot;</span> <span class="attr">value-ref</span>=<span class="string">&quot;car1&quot;</span>/&gt;</span></span><br><span class="line">			<span class="comment">&lt;!-- 方式三：在entry标签内部直接写bean去作为它的值 --&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;key03&quot;</span>&gt;</span></span><br><span class="line">				<span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Car&quot;</span>&gt;</span></span><br><span class="line">					<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;carName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;honda&quot;</span>/&gt;</span></span><br><span class="line">					<span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;price&quot;</span> <span class="attr">value</span>=<span class="string">&quot;5200&quot;</span>/&gt;</span></span><br><span class="line">				<span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;/<span class="name">entry</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;/<span class="name">map</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>



<h4 id="3-4-注解驱动开发"><a href="#3-4-注解驱动开发" class="headerlink" title="3.4 注解驱动开发"></a>3.4 注解驱动开发</h4><p>从Spring Framework3.0之后引入了大量注解，可以使用注解驱动的方式来代替原来的xml配置，这也是后来比较常见的一种配置方式。 </p>
<h5 id="1）配置类"><a href="#1）配置类" class="headerlink" title="1）配置类"></a>1）配置类</h5><p>注解驱动需要的是<strong>配置类</strong>，一个配置类就可以理解为一个 xml ，只要在类上标注一个 <code>@Configuration</code> ，这个类即是配置类。而在xml中我们使用的是bean标签来声明bean，而在注解驱动中只需要在方法上标注<code>@Bean</code>即可代表bean的声明。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfClass</span> </span>&#123;</span><br><span class="line">    <span class="comment">//默认方法名为bean的id，如果使用 @Bean(&quot;xx&quot;) 则代表xx为bean的id</span></span><br><span class="line">    <span class="comment">//返回值类型为bean的类型</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Person <span class="title">person</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Person();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这就相当于创建了一个xml文件，并在IoC容器中注册了id为person的Person类。</p>
<h5 id="2）依赖查找"><a href="#2）依赖查找" class="headerlink" title="2）依赖查找"></a>2）依赖查找</h5><p>在完成配置类之后，依赖的查找需要用到<code>AnnotationConfigApplicationContext</code>来初始化加载容器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ApplicationContext context = <span class="keyword">new</span> AnnotationConfigApplicationContext(ConfClass.class);</span><br><span class="line">Person person = (Person)context.getBean(<span class="string">&quot;person&quot;</span>);</span><br><span class="line">System.out.println(person);</span><br></pre></td></tr></table></figure>

<h5 id="3）依赖注入"><a href="#3）依赖注入" class="headerlink" title="3）依赖注入"></a>3）依赖注入</h5><p>方式一：基于Setter方法的注入</p>
<p>只需要在方法中使用set方法对属性进行赋值，将赋值属性之后的对象返回即可。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Person <span class="title">person</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Person person = <span class="keyword">new</span> Person();</span><br><span class="line">    person.setName(<span class="string">&quot;zs&quot;</span>);</span><br><span class="line">    person.setAge(<span class="number">11</span>);</span><br><span class="line">    <span class="keyword">return</span> person;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>方式二：基于构造函数的注入</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Person <span class="title">person</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Person(<span class="string">&quot;zs&quot;</span>,<span class="number">11</span>,<span class="string">&quot;135111&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="4）组件注册"><a href="#4）组件注册" class="headerlink" title="4）组件注册"></a>4）组件注册</h5><p>当我们需要注册的bean越来越多的时候，写很多方法标注很多的bean注解是不现实的。因此Spring中也提供了一些模式注解，可以实现对组件的快速注册。最基本的就是<code>@Component</code>注解，代表的是被注解的类会被注册到IoC容器中作为一个 Bean ，也就是说我们可以直接在Person实体类上标注该注解，那么就不用手动去写bean注解标注的方法进行注册。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这样配置之后默认是将Person类注册到IoC容器中，id为类名的小驼峰式，如果想指定id，可以使用 <code>@Component(&quot;xx&quot;)</code>声明。 </p>
<h5 id="5）组件扫描"><a href="#5）组件扫描" class="headerlink" title="5）组件扫描"></a>5）组件扫描</h5><p>在声明组件之后，还需要进行组件的扫描才能让IoC容器感知到组件的存在。我们可以直接在配置类上配置多一个<code>@ComponentScan(&quot;xx&quot;)</code>注解，xx为包路径，指定需要扫描的包及其子包。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;top.jtszt.bean&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfClass</span> </span>&#123; &#125;</span><br></pre></td></tr></table></figure>

<p>还可以在创建<code>AnnotationConfigApplicationContext</code>对象时传入包路径，这样也可以进行组件扫描。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ApplicationContext context = <span class="keyword">new</span> AnnotationConfigApplicationContext(<span class="string">&quot;top.jtszt.bean&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>除了使用注解驱动有组件扫描之外，基于xml配置也可以进行组件扫描</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">beans</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;top.jtszt.bean&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="6）声明bean的几个注解"><a href="#6）声明bean的几个注解" class="headerlink" title="6）声明bean的几个注解"></a>6）声明bean的几个注解</h5><p>@Component ：通用的注解，可标注任意类为 Spring 组件。</p>
<p>@Repository : 对应持久层即 Dao 层，主要用于数据库相关操作。</p>
<p>@Service : 对应服务层，主要涉及一些复杂的逻辑，需要用到 Dao层。</p>
<p>@Controller : 对应 Spring MVC 控制层，主要用户接受用户请求并调用 Service 层返回数据。</p>
<h5 id="7）-注解与xml梦幻联动"><a href="#7）-注解与xml梦幻联动" class="headerlink" title="7） 注解与xml梦幻联动"></a>7） 注解与xml梦幻联动</h5><p>在xml中开启注解配置，并声明配置类</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">beans</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">context:annotation-config</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.annotation.ConfClass&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在配置类上使用注解<code>@ImportResource</code>引入xml文件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ImportResource(&quot;classpath:applicationcontext.xml&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfClass</span> </span>&#123; &#125;</span><br></pre></td></tr></table></figure>

<h4 id="3-5-依赖注入的其他姿势（基于注解）"><a href="#3-5-依赖注入的其他姿势（基于注解）" class="headerlink" title="3.5 依赖注入的其他姿势（基于注解）"></a>3.5 依赖注入的其他姿势（基于注解）</h4><h5 id="1）注解式属性注入"><a href="#1）注解式属性注入" class="headerlink" title="1）注解式属性注入"></a>1）注解式属性注入</h5><p>在对@Component扫描进去的组件进行属性注入时，可以使用<code>@Value(&quot;xx&quot;)</code>注解标在对应属性上对属性进行信息注入，并且该实体类可以不带Setter方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;zs&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@Value(&quot;12&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="meta">@Value(&quot;132111&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String phone;</span><br><span class="line">    <span class="comment">//重写toString</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="2）从外部配置文件注入"><a href="#2）从外部配置文件注入" class="headerlink" title="2）从外部配置文件注入"></a>2）从外部配置文件注入</h5><p>在Spring中从外部配置文件读取信息之后注入给属性也是被允许的。首先需要使用<code>@PropertySource(&quot;xx&quot;)</code>注解标注在类上，其中xx代表配置文件的位置。之后在属性上使用<code>@Value(&quot;$&#123;yy&#125;&quot;)</code>注解进行注入，其中yy代表该值对应在配置文件中的key。</p>
<p>①在类路径下创建一个配置文件my.properties</p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">person.name</span>=<span class="string">ls</span></span><br><span class="line"><span class="meta">person.age</span>=<span class="string">16</span></span><br><span class="line"><span class="meta">person.phone</span>=<span class="string">135123</span></span><br></pre></td></tr></table></figure>

<p>②在实体类上标注@PropertySource(“classpath:my.properties”)</p>
<p>③在对应属性上标注@Value进行取值</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@PropertySource(&quot;classpath:my.properties&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;person.name&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;person.age&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;person.phone&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String phone;</span><br><span class="line">    <span class="comment">//重写toString</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="3）SpEL实现注入"><a href="#3）SpEL实现注入" class="headerlink" title="3）SpEL实现注入"></a>3）SpEL实现注入</h5><p>SpEL也就是Spring表达式语言 ，它从Spring3.0开始被支持，SpEL支持调用属性值、属性参数以及方法调用、数组存储、逻辑计算等功能。SpEL 的语法统一用 #{xx} 表示，xx为表达式。</p>
<p>最常见的是使用SpEL对bean属性的引用或者方法的调用。</p>
<p>例：现在有两个实体类Bird与Dog，我们可以使用SpEL将Bird的age属性注入到Dog的age属性中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Bird</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;16&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String age;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Dog</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Value(&quot;#&#123;bird.age&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String age;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="3-6-自动注入"><a href="#3-6-自动注入" class="headerlink" title="3.6  自动注入"></a>3.6  自动注入</h4><h5 id="1）-Autowired"><a href="#1）-Autowired" class="headerlink" title="1）@Autowired"></a>1）@Autowired</h5><p>在 bean 中直接在属性或者Setter方法上标注 <code>@Autowired</code> 注解，IoC 容器会按照属性对应的类型，从容器中找对应类型的 bean 赋值到对应的属性上，实现自动注入。</p>
<p>如果容器中找不到对应类型的bean，那么会抛出NoSuchBeanDefinitionException异常，也可以在该注解上加上<code>required = false</code> ，那么找不到bean时会注入null。 </p>
<p>假设有一个Car类，现在Person类有一个属性叫car，要对它实现自动注入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Car car;</span><br><span class="line">    <span class="comment">//重写toString</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>★Autowired注入的原理：</p>
<p>首先会拿到该属性的类型去IoC容器中找，如果找到一个则返回；如果找不到就抛异常(找不到bean)；如果找到多个，那么会根据属性id去容器中找有没有对应的id，如果有就返回，没有就抛异常(该类型bean不唯一)。</p>
<h5 id="2）-Qualifier"><a href="#2）-Qualifier" class="headerlink" title="2）@Qualifier"></a>2）@Qualifier</h5><p>如果容器中存在多个类型相同的bean（且id不匹配）将会注入失败。这时可以使用<code>@Qualifier</code>注解显式地指定要注入哪一个bean。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="meta">@Qualifier(&quot;bmw&quot;)</span></span><br><span class="line"><span class="keyword">private</span> Car car;</span><br></pre></td></tr></table></figure>

<h5 id="3）-Primary"><a href="#3）-Primary" class="headerlink" title="3）@Primary"></a>3）@Primary</h5><p>除了使用@Qualifier之外，还可以在被注入的 Bean 上标注@Primary，可以指定默认注入的Bean。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ComponentScan(&quot;top.jtszt.bean&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfClass</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@Primary</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Car <span class="title">bmw</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Car();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="4）-Resource"><a href="#4）-Resource" class="headerlink" title="4）@Resource"></a>4）@Resource</h5><p><code>@Resource</code> 来自JSR250规范，它与 <code>@Autowired</code> 的不同之处在于：<code>@Autowired</code> 是按照类型注入，<code>@Resource</code> 是直接按照属性名 / Bean的名称注入，相当于<code>@Autowired</code> 和 <code>@Qualifier</code>的结合。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource(name=&quot;benz&quot;)</span></span><br><span class="line"><span class="keyword">private</span> Car carCar;</span><br></pre></td></tr></table></figure>

<h5 id="5）-Inject"><a href="#5）-Inject" class="headerlink" title="5）@Inject"></a>5）@Inject</h5><p><code>@Inject</code>来自JSR330规范，使用前需要导入javax.inject依赖。使用上等同于<code>@Autowired</code>，但由于它是JSR的规范，因此不受Spring框架的限制。</p>
<h4 id="3-7-DI与DL的异同"><a href="#3-7-DI与DL的异同" class="headerlink" title="3.7 DI与DL的异同"></a>3.7 DI与DL的异同</h4><ul>
<li><strong>作用目标不同</strong><ul>
<li>依赖注入的作用目标通常是类成员</li>
<li>依赖查找的作用目标可以是方法体内，也可以是方法体外</li>
</ul>
</li>
<li><strong>实现方式不同</strong><ul>
<li>依赖注入通常借助一个上下文被动的接收</li>
<li>依赖查找通常主动使用上下文搜索</li>
</ul>
</li>
</ul>
<h4 id="3-8-bean高级"><a href="#3-8-bean高级" class="headerlink" title="3.8 bean高级"></a>3.8 bean高级</h4><h5 id="1）bean的作用域"><a href="#1）bean的作用域" class="headerlink" title="1）bean的作用域"></a>1）bean的作用域</h5><p><strong>singleton：</strong>单实例的bean在容器创建好之前就已经完成创建，并且在容器中只有单一的对象；</p>
<p><strong>prototype：</strong>多实例的bean只有在调用相关方法获取bean时才会被创建，并且获取一次创建一个；</p>
<p><strong>request :</strong> 每一次HTTP请求都会产生一个新的bean，该bean仅在当前HTTP request内有效；</p>
<p><strong>session :</strong> 每一次HTTP请求都会产生一个新的 bean，该bean仅在当前 HTTP session 内有效；</p>
<p><strong>global-session：</strong> 全局session作用域，仅仅在基于portlet的web应用中才有意义，Spring5已经没有了。Portlet是能够生成语义代码(例如：HTML)片段的小型Java Web插件。它们基于portlet容器，可以像servlet一样处理HTTP请求。但是，与 servlet 不同，每个 portlet 都有不同的会话。</p>
<p>在bean的配置中可以通过scope属性指定单实例/多实例。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--bean的作用域默认是单实例（singleton） --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;car1&quot;</span> <span class="attr">class</span>=<span class="string">&quot;top.jtszt.bean.Car&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;prototype&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<h5 id="2）bean的类型"><a href="#2）bean的类型" class="headerlink" title="2）bean的类型"></a>2）bean的类型</h5><p><strong>①普通bean</strong></p>
<p>类似前面创建的那些bean都是普通bean</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123; ... &#125;</span><br></pre></td></tr></table></figure>

<p><strong>②工厂bean</strong></p>
<p>所谓工厂bean就是在bean对象创建过于复杂，或者有一些特殊策略时借助<code>FactoryBean</code> 使用工厂方法来创建bean。<code>FactoryBean</code> 接口是一个创建对象的工厂，如果 Bean 实现了 <code>FactoryBean</code> 接口，则它本身将不再是一个普通的 Bean ，不会在实际的业务逻辑中起作用，而是由创建的对象来起作用。</p>
<p>FactoryBean接口有三个方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">FactoryBean</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="comment">// 返回创建的对象</span></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="function">T <span class="title">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 返回创建的对象的类型（即泛型类型）</span></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    Class&lt;?&gt; getObjectType();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建的对象是单实例Bean还是原型Bean，默认单实例</span></span><br><span class="line">    <span class="function"><span class="keyword">default</span> <span class="keyword">boolean</span> <span class="title">isSingleton</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>★关于FactoryBean的几个注意点：</strong></p>
<ul>
<li>它创建的bean直接放在 IoC 容器中</li>
<li>它的加载是伴随IoC容器的初始化时机一起的，也就是在容器生成好之前就创建</li>
<li>它生产bean的机制是延迟生产，只有调用方法获取bean时才会创建</li>
<li>使用它生产出来的bean默认是单实例的</li>
</ul>
<p><strong>★BeanFactory 和FactoryBean 的区别：</strong></p>
<p>BeanFactory：从类的继承结构上看，它是实现Spring最顶层的容器实现；从类的组合结构上看，它是最深层次的容器，ApplicationContext 在最底层组合了 BeanFactory 。</p>
<p>FactoryBean ：创建对象的工厂 bean ，可以使用它来直接创建一些初始化流程比较复杂的对象。</p>
<h5 id="3）bean的生命周期"><a href="#3）bean的生命周期" class="headerlink" title="3）bean的生命周期"></a>3）bean的生命周期</h5><ul>
<li><p>Bean 容器找到配置文件中 Spring Bean 的定义。</p>
</li>
<li><p>Bean 容器利用 Java Reflection API 创建一个Bean的实例。</p>
</li>
<li><p>如果涉及到一些属性值 利用 <code>set()</code>方法设置一些属性值。</p>
</li>
<li><p>如果 Bean 实现了 <code>BeanNameAware</code> 接口，调用 <code>setBeanName()</code>方法，传入Bean的名字。</p>
</li>
<li><p>如果 Bean 实现了 <code>BeanClassLoaderAware</code> 接口，调用 <code>setBeanClassLoader()</code>方法，传入 <code>ClassLoader</code>对象的实例。</p>
</li>
<li><p>与上面的类似，如果实现了其他 <code>*.Aware</code>接口，就调用相应的方法。</p>
</li>
<li><p>如果有和加载这个 Bean 的 Spring 容器相关的 <code>BeanPostProcessor</code> 对象，执行<code>postProcessBeforeInitialization()</code> 方法</p>
</li>
<li><p>如果Bean实现了<code>InitializingBean</code>接口，执行<code>afterPropertiesSet()</code>方法。</p>
</li>
<li><p>如果 Bean 在配置文件中的定义包含 init-method 属性，执行指定的方法。</p>
</li>
<li><p>如果有和加载这个 Bean的 Spring 容器相关的 <code>BeanPostProcessor</code> 对象，执行<code>postProcessAfterInitialization()</code> 方法</p>
</li>
<li><p>当要销毁 Bean 的时候，如果 Bean 实现了 <code>DisposableBean</code> 接口，执行 <code>destroy()</code> 方法。</p>
</li>
<li><p>当要销毁 Bean 的时候，如果 Bean 在配置文件中的定义包含 destroy-method 属性，执行指定的方法。<a target="_blank" rel="noopener" href="https://snailclimb.gitee.io/javaguide-interview/#/./docs/e-1spring?id=spring-%e4%b8%ad%e7%9a%84-bean-%e7%94%9f%e5%91%bd%e5%91%a8%e6%9c%9f">引用</a></p>
<p>  <img src="http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-17/5496407.jpg"></p>
<p>  <img src="https://www.hualigs.cn/image/6102ea407da4d.jpg"></p>
</li>
</ul>
<h5 id="4）bean的实例化方式"><a href="#4）bean的实例化方式" class="headerlink" title="4）bean的实例化方式"></a>4）bean的实例化方式</h5><p>①直接通过 <code>&lt;bean&gt;</code>标签 或者 <code>@Bean</code>、 <code>@Component</code>注解 注册 bean 后实例化</p>
<p>②借助 <code>FactoryBean</code> 实例化 bean</p>
<p>③使用静态工厂方法 <code>factory-method</code>实例化 bean</p>
<p>④使用实例工厂方法<code>factory-bean</code> + <code>factory-method</code> 实例化 bean</p>
<h5 id="5）单实例bean的线程安全问题"><a href="#5）单实例bean的线程安全问题" class="headerlink" title="5）单实例bean的线程安全问题"></a>5）单实例bean的线程安全问题</h5><p>默认情况下单实例 bean 的线程是不安全的（ 只要有可能变动的成员属性 ），也就是说如果在单实例bean的全局层面上定义有数据存储功能的对象 / 基本类型变量 / static变量，那么就会存在线程不安全的问题。</p>
<p>解决方法：</p>
<ul>
<li>通过声明Bean的 Scope=”prototype”，将bean变成多实例 </li>
<li>使用本地变量 ThreadLocal 进行定义</li>
</ul>
<hr>
<p><em>参考资料：</em></p>
<ul>
<li><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-framework/docs/5.1.3.RELEASE/spring-framework-reference/">Spring Framework 5.1.3.RELEASE文档</a></li>
<li><a target="_blank" rel="noopener" href="https://juejin.cn/book/6857911863016390663/section">从 0 开始深入学习 Spring-掘金小册</a></li>
<li><a target="_blank" rel="noopener" href="https://snailclimb.gitee.io/javaguide-interview/#/./docs/e-1spring">JavaGuide-Spring</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/vipshop_fin_dev/article/details/109017732">Spring中单例Bean的线程安全问题-CSDN</a></li>
<li><a target="_blank" rel="noopener" href="https://www.cnblogs.com/zrtqsk/p/3735273.html">Spring Bean的生命周期-博客园</a></li>
<li><a target="_blank" rel="noopener" href="https://javadoop.com/post/spring-ioc">Spring IOC 容器源码分析_Javadoop</a></li>
<li><a target="_blank" rel="noopener" href="https://blog.csdn.net/lj1314ailj/article/details/80118372">Spring5 系统架构-CSDN</a></li>
<li><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1d4411g7tv?p=256">雷丰阳Spring、Spring MVC、MyBatis课程-bilibili</a></li>
</ul>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">h0ss</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://blog.gpnusz.cn/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-2-IoC/">https://blog.gpnusz.cn/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-2-IoC/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://blog.gpnusz.cn" target="_blank">后端学习记录</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Spring/">Spring</a></div><div class="post_share"></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-3-AOP/"><img class="prev-cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Spring学习(3)AOP</div></div></a></div><div class="next-post pull-right"><a href="/2021/07/30/Spring%E5%AD%A6%E4%B9%A0-1-%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/"><img class="next-cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Spring学习(1)快速上手</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/2022/04/13/【解决方案】细说分片上传与极速秒传-SpringBoot-Vue/" title="【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)"><img class="cover" src="https://i.loli.net/2021/09/01/KHSB3kcFZDQx4vo.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-04-13</div><div class="title">【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)</div></div></a></div><div><a href="/2021/08/01/SpringMVC学习笔记/" title="SpringMVC学习笔记"><img class="cover" src="https://static01.imgkr.com/temp/07cc3f2f859f40ef8733044657da8465.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-08-01</div><div class="title">SpringMVC学习笔记</div></div></a></div><div><a href="/2021/07/30/Spring学习-3-AOP/" title="Spring学习(3)AOP"><img class="cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-07-30</div><div class="title">Spring学习(3)AOP</div></div></a></div><div><a href="/2021/07/30/Spring学习-1-快速上手/" title="Spring学习(1)快速上手"><img class="cover" src="https://www.hualigs.cn/image/610c2015e15b8.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-07-30</div><div class="title">Spring学习(1)快速上手</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">h0ss</div><div class="author-info__description">一个苦逼后端仔的学习记录</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/h0ss"><i class="fab fa-github"></i><span>Gitee仓库</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">Java后端技术栈语雀文档：https://www.yuque.com/oliver-wdtb1/java</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/11/16/%E7%BB%99%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%86%E4%B8%AAPR/" title="给开源项目提了个PR">给开源项目提了个PR</a><time datetime="2022-11-15T17:28:40.000Z" title="发表于 2022-11-16 01:28:40">2022-11-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/09/03/%E3%80%90MySQL%E3%80%91InnoDB%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F/" title="【MySQL】InnoDB的行格式">【MySQL】InnoDB的行格式</a><time datetime="2022-09-02T18:17:38.000Z" title="发表于 2022-09-03 02:17:38">2022-09-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/08/21/%E3%80%90Debug%E3%80%91bitField-%E5%BC%95%E5%8F%91%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】bitField 引发的栈溢出排错记">【Debug】bitField 引发的栈溢出排错记</a><time datetime="2022-08-20T18:10:40.000Z" title="发表于 2022-08-21 02:10:40">2022-08-21</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/16/%E3%80%90RPC%E3%80%91%E8%AF%A6%E8%A7%A3SPI%E6%9C%BA%E5%88%B6/" title="【RPC】详解SPI机制">【RPC】详解SPI机制</a><time datetime="2022-07-15T18:51:57.000Z" title="发表于 2022-07-16 02:51:57">2022-07-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/14/%E3%80%90Redis%E3%80%91%E9%87%8D%E8%A6%81%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80/" title="【Redis】重要数据结构基础">【Redis】重要数据结构基础</a><time datetime="2022-07-13T17:22:08.000Z" title="发表于 2022-07-14 01:22:08">2022-07-14</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"></div><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script><script id="click-show-text" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-show-text.min.js" data-mobile="false" data-text="爱国,敬业,诚信,友善,自由,平等,公正,法治,富强,民主,文明,和谐" data-fontsize="16px" data-random="false" async="async"></script></div></body></html>